package com.zjhcsoft.zjpr.amovie.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;



public class FtpUtil {
	private static Logger LOG = Logger.getLogger(FtpUtil.class);
	private FTPClient ftpClient = new FTPClient();  
	public static String PORT = "PORT"; 
	public static String PAVT = "PAVT";
	
	 
	/**
	 *  从FTP服务器上下载文件
	 * @param localFile @see File 本地文件
	 * @param remote  远程文件路径  
	 * @return
	 * @throws IOException
	 */
	public String downloadFile(File localFile, String remote)
			throws IOException {
		// 设置以二进制方式传输
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		ftpClient.setConnectTimeout(300000);
		String result = "";
		if ((result = checkLocalFileAndDelete(localFile)) != null) {
			return result;
		}

		if ((remote = checkFileBackAP(remote)) == null) {
			LOG.debug("the file [" + remote
					+ "] is not exist! on the ftp server!");
			return "File_Not_exist";
		}

		OutputStream out = new FileOutputStream(localFile);
		try {
			boolean issucess = ftpClient.retrieveFile(
					new String(remote.getBytes(Encoding), "Utf-8"), out);
			if (issucess) {
				LOG.debug("download the file [" + localFile.getName()
						+ "] : success");
				result = "Download_New_Success";
			} else {
				LOG.debug("download the file [" + localFile.getName()
						+ "] : failed !");
				result = "Download_New_Failed";
			}

			return result;
		} finally {
			out.close();
		}
	}
    
	public enum RemoteExist{
		OVERRID,NOCOPY,RENAME
	}
	
	/**
	 * 
	 * @param localFile 本地文件
	 * @param exist  如果文件存在  OVERRID,NOCOPY,RENAME
	 * @return
	 * @throws IOException 
	 */
	public boolean uploadFile(File localFile, String remotepath,
			RemoteExist exist) throws IOException {
		if(!remotepath.endsWith("/")){
			remotepath += "/";
		}
		if (!localFile.exists()) {
			LOG.error("the local file [" + localFile.getName()+ "] is not exist!");
			return false;
		}
		
		if(!checkDirectoryAndCreate(remotepath)){
			LOG.error("Conn't create the directory on the FTP server");
			return false;
		}
		boolean backBoolean = false;
		if (checkFileBackAP(remotepath + localFile.getName()) == null) {
			backBoolean = upload(remotepath + localFile.getName(), localFile);
		}
		else{
			LOG.error("upload the file["+localFile.getName()+"] with "+exist+" mothed!");
			backBoolean = uploadExist(localFile, remotepath, exist);
		}
		return backBoolean;
	}
	
	/**
	 * 
	 * @param remotepath
	 * @return
	 * @throws IOException
	 */
	private boolean checkDirectoryAndCreate(String remotepath) throws IOException {
		boolean isSuccess = ftpClient.changeWorkingDirectory(remotepath);
		if(!isSuccess){
			if(!ftpClient.makeDirectory(remotepath)){
				return false;
			}
		}
		return true;
	}
	 
	/**
	 * 
	 * @param localFile
	 * @param remotepath
	 * @param exist
	 * @return
	 * @throws IOException
	 */
	private boolean uploadExist(File localFile, String remotepath,
			RemoteExist exist) throws IOException {
		boolean isSuccess = false;
		switch (exist) {
		case OVERRID:
			isSuccess = deleteFile(remotepath + localFile.getName());
			if(!isSuccess){
				LOG.error("can't delete the remote file [" + localFile.getName()+ "] and the file will not upload!");
				isSuccess = false;
				break;
			}
			upload(remotepath + localFile.getName(), localFile);
			break;
		case RENAME:
			String name = localFile.getName();
			name = checkFileAndReName(localFile.getName(), remotepath, 1);
			LOG.error("change the file that will be uploaded name is :"+name+" !");
			isSuccess = upload(remotepath + name, localFile);
			break;
		case NOCOPY:

		default:
			LOG.error("the remote file [" + localFile.getName()+ "] be existed and the file will not upload!");
			return false;
		}
		return isSuccess;
	}
	
	/**
	 * 
	 * @param filename
	 * @param remotepath
	 * @param i
	 * @return
	 * @throws IOException
	 */
	private String checkFileAndReName(String filename,String remotepath,int i) throws IOException{
		String newName = filename.substring(0, filename.lastIndexOf('.')) + "("+i+")"+ filename.substring(filename.lastIndexOf('.'));
		if (checkFileBackAP(remotepath + newName) == null) {
			return newName;
		}
		return checkFileAndReName(filename,remotepath,++i);
	}
	
	/**
	 * 
	 * @param remoteFile
	 * @param localFile
	 * @return
	 * @throws IOException
	 */
	public boolean upload(String remoteFile, File localFile) throws IOException {
		InputStream is = null;
		try {
			is = new FileInputStream(localFile);
			ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
			ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
			boolean status = ftpClient.storeFile(remoteFile, is);
			return status;
		} finally {
			if (is != null)
				is.close();
		}
	}
	
	/**
	 * 
	 * @param filename  文件路径
	 * @return
	 * @throws IOException
	 */
	public boolean deleteFile(String filename) throws IOException {
		return ftpClient.deleteFile(filename);
	}
	
	/**
	 * 
	 * @param remotepath
	 * @return
	 * @throws IOException
	 */
	public String[] getListName(String remotepath) throws IOException{
		return  ftpClient.listNames(remotepath);
	}

	/**
	 * this method be useed connection the ftp server.
	 * After complete action, must call disconnect();
	 * @param remoteAddr 服务器地址
	 * @param port  端口
	 * @param username  用户名
	 * @param passwd  用户密码
	 * @param ftpmode  连接模式。取值为  one of PORT,PAVT;
	 * @return 
	 * @throws IOException 
	 * @throws SocketException 
	 */
	public boolean connect(String remoteAddr, int port, String username,
			String passwd, String ftpmode) throws SocketException, IOException {
		ftpClient.connect(remoteAddr, port);
		ftpClient.setControlEncoding(Encoding);
		if (PAVT.equals(ftpmode))
			ftpClient.enterLocalPassiveMode();
		else if (PORT.equals(ftpmode))
			ftpClient.enterLocalActiveMode();
		if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
			if (ftpClient.login(username, passwd)) {
				return true;
			}
		}
		disconnect();
		return false;
	}
	
	/**
	 * 
	 * @return
	 * @throws IOException
	 */
	public boolean disconnect() throws IOException{
		if(ftpClient.isConnected()){
			ftpClient.logout();
			ftpClient.disconnect();
			return true;
		}
		return false;
	} 
	
	/**
     * 本地存在文件，则先删除     
     * @param localFile
     * @return
     */
	private String checkLocalFileAndDelete(File localFile) {
        if(localFile.exists()){
        	boolean is_delete_success = false;
        	try{
        		is_delete_success = localFile.delete();        	
        	} catch(Throwable e){
        		LOG.error("",e);
        	}
        	if (!is_delete_success){
        		LOG.error("无法删除本地文件" + localFile.getName());
        		return "Local_File_Delete_Failed";
        	}
        }
        return null;
	}

    /**
     * 
     * @param remote
     * @throws IOException
     * @return if the file exist on the ftp server,return the file absolute Path,otherwise return null!
     */
	private String checkFileBackAP(String remote) throws IOException {
		int index = remote.lastIndexOf('/');
		String fileName = null;
		String filepath = null;
		String[] ftpfileNames = null;
		String absolutePath = remote;
		String defaultPath  = ftpClient.printWorkingDirectory();
		if(index != -1){
			fileName = remote.substring(index+1);
			filepath = remote.substring(0,index+1);
			ftpfileNames = getListName(filepath);
		}
		else{
			fileName = defaultPath+remote;
			absolutePath = defaultPath+"/"+remote;
			ftpfileNames = getListName(defaultPath);
		}
		
		if(ftpfileNames == null){
			 return null;
		}
		
        for (String string : ftpfileNames) {
			if(fileName.equals(string)){
				return absolutePath;
			}
		}
        return null;
	}  
	
	private String Encoding = "GBK";

	public String getEncoding() {
		return Encoding;
	}

	public void setEncoding(String encoding) {
		Encoding = encoding;
	}
}